package com.logistics.account.service;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.logistics.account.entity.model.*;
import com.logistics.account.mapper.AccountMapper;
import com.logistics.account.entity.domain.Account;
import com.logistics.erp.entity.domain.ErpUser;
import com.logistics.erp.entity.model.ErpPersonRow;
import com.logistics.erp.service.ErpOrderService;
import com.logistics.erp.service.ErpUserService;
import com.logistics.organization.service.OrganizationService;
import com.logistics.sequence.service.SequenceService;
import com.logistics.utils.aspect.annotation.Insert;
import com.logistics.utils.aspect.annotation.Pager;
import com.logistics.utils.bean.ResultPager;
import com.logistics.utils.bean.UserBean;
import com.logistics.utils.configure.Configure;
import com.logistics.utils.constants.Dictionary;
import com.logistics.utils.constants.Message;
import com.logistics.utils.exception.MessageException;
import com.logistics.utils.jwt.JwtRegistry;
import com.logistics.utils.message.Manager;
import com.logistics.utils.redis.RedisService;
import com.logistics.utils.security.EncryptionUtils;
import com.logistics.utils.tool.StringUtils;
import com.logistics.utils.tool.UserUtils;
import com.logistics.utils.webservice.annotation.WebServiceListener;
import com.logistics.utils.webservice.annotation.WebServiceMethod;
import io.jsonwebtoken.ExpiredJwtException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@WebServiceListener
public class AccountService extends ServiceImpl<AccountMapper, Account> {

    @Autowired
    private JwtRegistry jwtRegistry;

    @Autowired
    private Configure configure;

    @Autowired
    private RedisService redisService;

    @Autowired
    private AccountRoleService accountRoleService;

    @Autowired
    private OrganizationService organizationService;

    @Autowired
    private SequenceService sequenceService;

    @Autowired
    private CacheManager cacheManager;

    @Autowired
    private ErpOrderService erpOrderService;

    @Autowired
    private UserUtils userUtils;
    @Autowired
    private ErpUserService erpUserService;

    /**
     * 用户登录
     * @param model
     * @throws MessageException
     */

    public Map loginCheck(LoginModel model) throws Exception{
        if(StringUtils.isNull(model.getAccount())){
            throw new MessageException(Manager.getMessage(Message.MSG1001.getCode()));
        }
        if(StringUtils.isNull(model.getPassword())){
            throw new MessageException(Manager.getMessage(Message.MSG1002.getCode()));
        }
        Account result = this.getOne(new LambdaQueryWrapper<Account>().
                eq(Account::getAccount, model.getAccount())
                .eq(Account::getPassword, EncryptionUtils.md5Encode(model.getPassword())));
        if(StringUtils.isNull(result)){
//            ErpPersonRow personRow = erpOrderService.userInfoByCodeAndPw(model.getAccount(), EncryptionUtils.md5Encode(model.getPassword()));
//            if(StringUtils.isNull(personRow)){
//                throw new MessageException(Manager.getMessage(Message.MSG1003.getCode()));
//            }
//            this.save(AccountSave.build(model.getAccount(), model.getPassword(), personRow.getPersonName(), personRow.getDeptCode()));
            throw new MessageException(Manager.getMessage(Message.MSG1003.getCode()));
        }
        String token = jwtRegistry.createToken(jwtRegistry.generalSubject(UserBean.build(result)));
        setLongToken(token, result);
        Map<String, Object> res = new HashMap<>();
        res.put("token", token);
        res.put("userId", result.getId());
        res.put("userName", result.getUserName());
        return res;
    }

    /**
     * api开放接口token 获取
     * @param account
     * @return
     */
    public Map<String, Object> apiToken(String account) throws Exception{
        Account result = this.getOne(new LambdaQueryWrapper<Account>().eq(Account::getAccount, account));
        if(StringUtils.isNull(result)){
            throw new MessageException("code码不正确");
        }
        Map<String, Object> res = new HashMap<>();
        res.put("token", jwtRegistry.createToken(jwtRegistry.generalSubject(result)));
        return res;
    }

    /**
     * 修改密码
     * @param password
     */
    public void updatePassword(String password){
        UserBean userBean = userUtils.getUserInfo();
        this.update(Account.build(EncryptionUtils.md5Encode(password)),
                new LambdaUpdateWrapper<Account>().eq(Account::getId, userBean.getUserId()));
    }

    /**
     * 检查token是否过期
     * @param token
     * @return
     */
    public Map<String, Object> checkToken(String token){
        Map<String, Object> result = new HashMap<>();
        boolean flag = true;
        try {
            jwtRegistry.parseJWT(token);
        } catch (ExpiredJwtException e){
            String refreshToken = configure.getRedisGate() ? redisService.getString(token) :
                    getRefreshToken(token);
            if(StringUtils.isNotNull(refreshToken)){
                try {
                    jwtRegistry.parseJWT(refreshToken);
                }catch (ExpiredJwtException ex){
                    flag = false;
                }
            }else{
                flag = false;
            }
        }
        result.put("flag", flag);
        return result;
    }

    /**
     * 获取spring boot 缓存
     * @return
     */
    private String getRefreshToken(String tokenKey){
        Cache cache = cacheManager.getCache("cache");
        if(StringUtils.isNull(cache.get(tokenKey))){
            return null;
        }
        Object refreshToken = cache.get(tokenKey).get();
        return StringUtils.isNotNull(refreshToken) ? refreshToken.toString() : null;
    }

    /**
     * 根据用户查找用户code
     * @param account
     * @return
     */
    public Map<String, String> codeByAccount(String account){
        Account result = this.getOne(new LambdaQueryWrapper<Account>().eq(Account::getAccount, account));
        if(StringUtils.isNull(result)){
            return null;
        }
        Map<String, String> res = new HashMap<>();
        res.put("code", result.getCode());
        res.put("organization", result.getOrganization());
        res.put("dep", result.getDep());
        return res;
    }

    /**
     * 查找所有的用户
     * @return
     */
    @WebServiceMethod
    public List<AccountRow> accountAll(){
        return this.list().stream().map(e-> AccountRow.build(e)).collect(Collectors.toList());
    }

    /**
     * 分页查询
     * @param param
     * @return
     */
    @Pager
    @WebServiceMethod
    public ResultPager pager(AccountPager param){
        IPage page = new Page(param.getCurrent(), param.getPageSize());
        QueryWrapper<Account> queryWrapper = new QueryWrapper<>();
        if(StringUtils.isNotNull(param.getAccount())){
            queryWrapper.lambda().like(Account::getAccount, param.getAccount());
        }
        if(StringUtils.isNotNull(param.getUserName())){
            queryWrapper.lambda().like(Account::getUserName, param.getUserName());
        }
        if(StringUtils.isNotNull(param.getMobile())){
            queryWrapper.lambda().eq(Account::getMobile, param.getMobile());
        }
        IPage<Account> result = this.page(page, queryWrapper.lambda().orderByDesc(Account::getCreateTime));
        return new ResultPager(result.getRecords().stream().
                map(e -> AccountRow.build(e)).collect(Collectors.toList()), (int) result.getTotal());
    }

    /**
     * 验证用户是否在使用要删除的组织机构
     * @param organizationIds
     * @throws MessageException
     */
    public void checkOrganization(List<String> organizationIds) throws MessageException {
        List<Account> list = this.list(new LambdaQueryWrapper<Account>()
                .in(Account::getOrganization, organizationIds).or().in(Account::getDep, organizationIds));
        if(list.size() > 0){
            throw new MessageException(Manager.getMessage(Message.MSG1012.getCode()));
        }
    }

    /**
     * 查找详细
     * @param id
     * @return
     */
    @WebServiceMethod
    public AccountRow details(String id) throws MessageException {
        if(StringUtils.isNull(id)){
            throw new MessageException(Manager.getMessage(Message.MSG1005.getCode()));
        }
        AccountRow row = AccountRow.build(this.getOne(new LambdaQueryWrapper<Account>().eq(Account::getId, id)));
        row.setRoleIds(accountRoleService.roleIdsByUserId(id));
        return row;
    }

    /**
     * 删除用户
     * @param ids
     * @throws MessageException
     */
    public void delete(String ids) throws MessageException {
        if(StringUtils.isNull(ids)){
            throw new MessageException(Manager.getMessage(Message.MSG1005.getCode()));
        }
        accountRoleService.delete(ids);
        this.remove(new LambdaQueryWrapper<Account>().in(Account::getId, StringUtils.splitToList(ids, ",")));
    }

    /**
     * 保存
     * @param save
     */
//    @Transactional
    @Insert
    public void save(AccountSave save) throws MessageException {
        Account user = this.getOne(new LambdaQueryWrapper<Account>().
                eq(Account::getAccount, save.getAccount()));
        ErpUser userByAccount = erpUserService.findUserByAccount(save.getAccount());
//        if(StringUtils.isNull(userByAccount)){
//            throw new MessageException("账号"+save.getAccount()+"在ERP系统中不存在，请确认");
//        }
        String userUniqueId = null;
        if(StringUtils.isNotNull(userByAccount)){
            userUniqueId = userByAccount.getUserUniqueId();
        }
        if(StringUtils.isNull(save.getId())){
            if(StringUtils.isNotNull(user)){
                throw new MessageException(Manager.getMessage(Message.MSG1010.getCode()));
            }
            Account account = Account.build(save);
            account.setCode(getUserCode(save.getDep()));
            account.setErpUniqueId(userUniqueId);
            //获取部门/班组编号
            account.setErpDeptCode(getWcCode(save.getDep()));
            this.save(account);
            save.setId(account.getId().toString());
        }else{
            Account modifyUser = this.getOne(new LambdaQueryWrapper<Account>().eq(Account::getId, save.getId()));
            if(StringUtils.isNull(modifyUser)){
                throw new MessageException(Manager.getMessage(Message.MSG1011.getCode()));
            }
            if(StringUtils.isNotNull(user) && !StringUtils.isEquals(user.getAccount(),
                    modifyUser.getAccount())){
                throw new MessageException(Manager.getMessage(Message.MSG1010.getCode()));
            }
            //获取部门/班组编号
            save.setErpDeptCode(getWcCode(save.getDep()));
            save.setErpUniqueId(userUniqueId);
            this.update(Account.build(save),
                    new LambdaQueryWrapper<Account>().eq(Account::getId, save.getId()));
        }
        // 删除角色
        accountRoleService.delete(save.getId());
        // 保存角色
        accountRoleService.save(StringUtils.splitToList(save.getRoleIds(), ",").stream()
                .map(e -> AccountRoleSave.build(save.getId(), e)).collect(Collectors.toList()));
    }

    /**
     * 设置长token
     * @param account
     * @throws Exception
     */
    private void setLongToken(String tokenKey, Account account) throws Exception {
        String token = getRefreshToken(account);
        if(configure.getRedisGate()){
            redisService.set(tokenKey, token,  configure.getToken().getLongTime());
        }else{
            cacheManager.getCache("cache").put(tokenKey, token);
        }
    }

    /**
     * 获取长token
     * @param account
     * @return
     * @throws Exception
     */
    public String getRefreshToken(Account account) throws Exception {
        return jwtRegistry.createToken(jwtRegistry.generalSubject(UserBean.build(account)),
                configure.getToken().getLongTime());
    }

    /**
     * 获取用户编码
     * @param depId
     * @return
     * @throws MessageException
     */
    private String getUserCode(String depId) throws MessageException {
        String depCode = organizationService.codeById(depId);
        String userCode = sequenceService.getCode(Dictionary.USER.getName(), 4);
        return depCode.concat(userCode);
    }

    private String getWcCode(String depId){
        return organizationService.wcCodeById(depId);
    }
}
